#ifndef DW_GRAFFITI_RENDERER_H
#	define DW_GRAFFITI_RENDERER_H

#include "base/singleton.h"

#include "enums.h"
#include "matrixstack.h"

namespace dw {

	namespace system {
		class Window;
	} // namespace system
	
	namespace graffiti {

struct Context;
struct ContextSetup;
class RenderWindow;

struct IndexBuffer;
struct VertexBuffer;
class Program;

class Renderer
:	public dw::base::Singleton< Renderer, false >
{
public : //! @name Types definitions
	//! @{
	typedef dw::base::Singleton< Renderer, false > base;
	//! @}

public : //! @name Life cycle commands
	//! @{
	RenderWindow* initialize(dw::system::Window* window);
	RenderWindow* initialize(dw::system::Window* window, const ContextSetup& setup);
	void terminate();
	//! @}

public : //! @name Setup
	//! @{
	void setProgram(Program* program);
	void setIndexBuffer(IndexBuffer* buffer);
	void setVertexBuffer(VertexBuffer* buffer);

	void setUniform(const std::string& name, const void* data);
	//! @}

public : //! @name Draw
	//! @{
	void drawIndexed(primitive::type::types type, dw::uint32 primitivesCount, dw::uint32 primitiveStart = 0);
	void drawIndexedBiased(primitive::type::types type, dw::uint32 primitivesCount, dw::uint32 indexBias, dw::uint32 primitiveStart = 0);
	//! @}

public : //! @name Matrix management
	//! @{
	void pushMatrix(matrix::matrices mode);
	void pushMatrix(matrix::matrices mode, const glm::mat4& mat);
	void popMatrix(matrix::matrices mode);
	void setMatrix(matrix::matrices mode, const glm::mat4& mat);
	void multMatrix(matrix::matrices mode, const glm::mat4& mat);

	const glm::mat4& getMatrix(matrix::matrices mode) const ;
	//! @}

private : //! @name Construction & Destruction
	//! @{
	Renderer();
	~Renderer();

	friend class base;
	//! @}

private : //! @name Internal helpers
	//! @{
	Context* createMainContext(const ContextSetup& setup);
	//! @}

private : //! @name Data
	//! @{
	MatrixStack* m_matrixStacks[3];
	mutable glm::mat4 m_modelview;
	mutable glm::mat4 m_modelviewproj;

	Context* m_mainContext;
	dw::system::Window* m_window;
	bool m_glewIsInitialized;

	Program* m_program;
	dw::uint32 m_missingAttributesHashcode;
	IndexBuffer* m_indexBuffer;
	//! @}
};

	} // namespace graffiti
} // namespace dw

#endif // !DW_GRAFFITI_RENDERER_H
